package com.bolt.report.engine.fill;

import com.bolt.common.collection.IteratorUtil;
import com.bolt.common.collection.MapUtil;
import com.bolt.common.convert.Convert;
import com.bolt.report.definition.CellDefinition;
import com.bolt.report.definition.ReportDefinition;
import com.bolt.report.definition.RowDefinition;
import com.bolt.report.definition.StyleDefinition;
import com.bolt.report.engine.BindData;
import com.bolt.report.engine.ObjectFactory;
import com.bolt.report.engine.ReportConstants;
import com.bolt.report.engine.model.Cell;
import com.bolt.report.engine.model.DataRange;
import com.bolt.report.engine.model.PageDetails;
import com.bolt.report.exception.ReportException;

import java.util.*;

public class DefaultReportFiller extends BaseReportFiller {

    //private ReportCacheManager cacheManager;

    public DefaultReportFiller(ReportDefinition definition) {
        super(definition);
    }


    protected void fillReport() throws ReportException {
        fillReportStart();
        fillContext();
        fillSummary();
        fillReportEnd();
    }

    protected void fillReportStart() {
        isFirstTitleToPrint = true;

        lastGroupCell = new ArrayList<>();
        fillColumn();
        addPage();
    }

    protected void fillContext() {
        fillTitle();
        fillColumnHeader();
        List<RowDefinition> rowDefinitions = definition.getElements();
        for (RowDefinition rowDefinition : rowDefinitions) {
            List<CellDefinition> staticCells = definition.getStaticCell(rowDefinition.getCellDefinitions(), fillContext);
            Map<String, List<CellDefinition>> dataCells = definition.getDataSetMap(rowDefinition.getCellDefinitions(), fillContext);
            List<CellDefinition> chartCells = definition.getChartCell(rowDefinition.getCellDefinitions());
            fillDataCell(dataCells, staticCells, chartCells, rowDefinition.getHeight());
        }
    }


    protected void fillDataCell(Map<String, List<CellDefinition>> dataCells, List<CellDefinition> staticCells, List<CellDefinition> chartCells, int rowHeight) {

        if (MapUtil.isNotEmpty(dataCells)) {
            for (Iterator<String> it = dataCells.keySet().iterator(); it.hasNext(); ) {
                dataIndex.set(0);
                String key = it.next();
                List<CellDefinition> cellDefinitions = dataCells.get(key);
                if (next(key)) {
                    do {
                        fillDataContent(cellDefinitions, staticCells, rowHeight);
                        dataIndex.incrementAndGet();
                    } while (next(key));
                    restart(key);
                } else {
                    //
                }
            }
        } else {
            dataIndex.set(0);
            if (IteratorUtil.isNotEmpty(staticCells)) {
                fillStaticCell(null, staticCells, rowHeight, true);
            }
        }

        if (IteratorUtil.isNotEmpty(chartCells)) {
            fillChartCell(chartCells, rowHeight);
        }
    }

    public void fillChartCell(List<CellDefinition> cellDefinitions, int rowHeight) {
        List<Cell> cells = new ArrayList<>(cellDefinitions.size());
        for (CellDefinition element : cellDefinitions) {
            Cell cell = ObjectFactory.createCell(element, fillContext, null, element.getY(), element.getX());
            StyleDefinition style = element.getStyle();
            cell.setStyle(style);
            cell.setRowSpan(element.getRowSpan());
            cell.setColSpan(element.getColSpan());
            cells.add(cell);
        }
        fillRow(cells, rowHeight);
    }


    protected void fillDataContent(List<CellDefinition> cellDefinitions, List<CellDefinition> textCells, int rowHeight) {
        List<Cell> cells = ObjectFactory.newEmptyValueList(this.columns.size());
        for (int index = 0; index < cellDefinitions.size(); index++) {
            CellDefinition element = cellDefinitions.get(index);
            Object value = getCurrentBindValue(element.getKey(), element.getName());
            BindData bindData = new BindData(element.getKey(), element.getName(), value, new DataRange(dataIndex.get(), dataIndex.get()));
            Cell cell = ObjectFactory.createCell(element, fillContext, bindData, dataIndex.get()+element.getY(), element.getX());
            StyleDefinition style = element.getStyle();
            cell.setStyle(style);
            cell.setColSpan(element.getColSpan());
            cell.setRowSpan(element.getRowSpan());
            cells.add(cell);
        }
        if (IteratorUtil.isNotEmpty(textCells)) {
            fillStaticCell(cells, textCells, rowHeight, false);
        }
        fillRow(cells, rowHeight);
    }


    protected void fillReportEnd() {
        reportPrint.removeLastEmptyPage();
        List<PageDetails> pages = reportPrint.getPages();
        for (int i = 0; i < pages.size(); i++) {
            PageDetails page = pages.get(i);
            Cell blankCell = page.getRowSpanCell();
            if (!Objects.isNull(blankCell)) {
                int fillRow = blankCell.getRowSpan();
                int fillColumn = blankCell.getColumnIndex();
                List<Cell> fillCell = new ArrayList<>();
                for (int r = page.getCurrentRowSize(); r < fillRow; r++) {
                    for (int c = 0; c < fillColumn; c++) {
                        fillCell.add(ObjectFactory.createBlankCell(r, c, fillContext));
                    }
                    page.insertCells(fillCell, page.getRow(blankCell.getRowIndex()).getHeight());
                }
            }
        }
    }


    protected void setIgnorePagination(Map<String, Object> parameterValues) {
        ignorePagination = Convert.toBool(parameterValues.get(ReportConstants.IS_IGNORE_PAGINATION), false);
    }


}